home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-02-07 | 68.1 KB | 1,925 lines | [TEXT/MPS ] |
- {-------------------------------------------------------------------------------
- #
- # Apple Macintosh Developer Technical Support
- #
- # ProcDoggie-specific Process Manager code
- #
- # Program: ProcDoggie
- # File: UProcessGuts.inc1.p - Pascal Implementation
- #
- # by: Forrest Tanaka
- #
- # Copyright © 1988-1991 Apple Computer, Inc.
- # All rights reserved.
- #
- -------------------------------------------------------------------------------}
- {[j=20/57/1$] Pasmat Options}
- {$R-}
-
-
- (*******************************************************************************
- * Constants
- *******************************************************************************)
-
- CONST
- rProcessListWindID = 128; {Resource ID of process list window template}
- rProcessInfoWindID = 129; {Resource ID of process info window template}
- rProcessInfoDitlID = 129; {Resource ID of process info dialog item list}
-
- kProcessListWindKind = 8; {In windowKind field of process list windows}
- kProcessInfoWindKind = 9; {In windowKind field of process info windows}
- kActivateList = TRUE; {Pass to LActivate to specify activate list}
- kScrollBarWidth = 16; {Width of scroll bar in pixels}
-
- rAppOrDAStringID = 128; {Resource ID of Application or DA string}
- kAppStringInd = 1; {Index for Application string}
- kDAStringInd = 2; {Index for Desk Accessory string}
-
- rCheckMarkID = 128; {Resource ID of checkmark string}
-
- kProcessNameItem = 1; {Dialog item # of process name}
- kAppOrDAItem = 2; {Dialog item # of Application/DA string}
- kTotalSizeItem = 5; {Dialog item # of Total Size readout}
- kFreeSpaceItem = 6; {Dialog item # of Free Space readout}
- kMemIndicatorItem = 7; {Dialog item # of partition memory indicator}
- kGrayLineItem0 = 8; {Dialog item # of first gray line}
- kTypeItem = 11; {Dialog item # of TYPE item}
- kCreatorItem = 12; {Dialog item # of Creator item}
- kGrayLineItem1 = 13; {Dialog item # of second gray line}
- kSusResChkItem = 14; {Dialog item # of suspend/resume checkmark}
- kWindActChkItem = 15; {Dialog item # of window activate checkmark}
- kGetClickChkItem = 16; {Dialog item # of Get front click checkmark}
- kAppDiedChkItem = 17; {Dialog item # of App Died checkmark}
- kStationeryChkItem = 18; {Dialog item # of Stationery checkmark}
- kCanBackChkItem = 19; {Dialog item # of Can Background checkmark}
- kOnlyBackChkItem = 20; {Dialog item # of Only Background checkmark}
- kHighLevelChkItem = 21; {Dialog item # of High-Level Evt checkmark}
- kRHighLevelChkItem = 22; {Dialog item # of Remote High-Level checkmark}
- kMultiUserChkItem = 23; {Dialog item # of Multi-user Launch checkmark}
- k32BitCleanChkItem = 24; {Dialog item # of 32-Bit Clean checkmark}
-
- kUsedColor = 2; {Process Info window palette color for used memory}
- kFreeColor = 3; {Process Info window palette color for free memory}
-
-
- (*******************************************************************************
- * Types
- *******************************************************************************)
-
- TYPE
- {Pointer to canonical format for number strings}
- NumFormatStringPtr = ^NumFormatString;
-
- {Pointer to process serial number}
- PSNPtr = ^ProcessSerialNumber;
-
-
- (*******************************************************************************
- * Variables
- *******************************************************************************)
-
- VAR
- gLaunchMode: LaunchModeCode; {Open documents? Print documents?}
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: SetLaunchMode
- *
- * The global variable, "gLaunchMode", is set to the launch mode specified by
- * "newMode".
- *******************************************************************************)
-
- PROCEDURE SetLaunchMode (newMode: LaunchModeCode);
-
- BEGIN
- gLaunchMode := newMode
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: GetLaunchMode
- *
- * The value of the global variable, "gLaunchMode", is returned.
- *******************************************************************************)
-
- FUNCTION GetLaunchMode: LaunchModeCode;
-
- BEGIN
- GetLaunchMode := gLaunchMode
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Public: IsProcessListWindow
- *
- * I store a unique code in the windowKind field of every window I create so that
- * I can identify the kind of window it is later… like now! I check to see if
- * the windowKind field of aWindow is kProcessListWindKind or not. If it is, I
- * know it’s a process list window, and so IsProcessListWindow returns TRUE.
- *******************************************************************************)
-
- FUNCTION IsProcessListWindow (aWindow: WindowPtr): Boolean;
-
- BEGIN
- IF aWindow <> NIL THEN
- IsProcessListWindow := WindowPeek(aWindow)^.windowKind =
- kProcessListWindKind
- ELSE
- IsProcessListWindow := FALSE
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: CreateProcessListWindow
- *
- * I store the constant kProcessListWindKind into the windowKind field of the new
- * window. When the routine IsProcessListWindow is called, it uses this field to
- * identify a window as a process list window.
- *
- * See the UWindowHandler unit for code to create a new window.
- *******************************************************************************)
-
- FUNCTION CreateProcessListWindow: WindowPtr;
-
- CONST
- kDrawList = TRUE; {Pass to LNew; list must be drawn immediately}
- kHasGrow = TRUE; {Pass to LNew; list has grow box}
- kHasHorzScroll = TRUE; {Pass to LNew; list has a horizontal scroll bar}
- kHasVertScroll = TRUE; {Pass to LNew; list has a vertical scroll bar}
-
- VAR
- aWindow: WindowPtr; {Pointer to the process list window}
- processList: ListHandle; {Handle to the list of processes}
- listRect: Rect; {Rectangle of list in window coords}
- listDimensions: Rect; {Dimensions of list in cells}
- cellSize: Point; {Size of cell in pixels}
- currFont: FontInfo; {Information about current port’s font}
-
- PROCEDURE HandleError (messageClass: Integer;
- messageIndex: Integer);
-
- VAR
- result: Integer; {Result of alert; ignored}
-
- BEGIN
- IF aWindow <> NIL THEN
- BEGIN
- CloseWindow (aWindow);
- DisposPtr (Ptr(aWindow))
- END;
- result := ShowStopAlert (messageClass, messageIndex);
- gError := noErr;
- CreateProcessListWindow := NIL;
- EXIT (CreateProcessListWindow)
- END;
-
- BEGIN
- aWindow := NIL;
-
- (* Create the new window *)
- aWindow := CreateWindow (rProcessListWindID);
- IF gError <> noErr THEN
- IF gError = memFullErr THEN
- HandleError (rMemErrMessages, kMemErrProcListOpenMsg)
- ELSE IF gError = resNotFound THEN
- HandleError (rResErrMessages, kResErrAppDamageMsg)
- ELSE IF gError = dsSysErr THEN
- HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
-
- (* Set up the window *)
- SetPort (aWindow);
- WindowPeek(aWindow)^.windowKind := kProcessListWindKind;
- TextFont (1);
-
- (* Create the process list *)
- GetFontInfo ((*<*)currFont);
- listRect := aWindow^.portRect;
- listRect.right := listRect.right - kScrollBarWidth + 1;
- SetRect ((*<*)listDimensions, 0, 0, 1, 0);
- cellSize.h := listRect.right - listRect.left;
- cellSize.v := currFont.ascent + currFont.descent + currFont.leading;
- processList := LNew (listRect, listDimensions, cellSize, 128, aWindow,
- kDrawList, NOT kHasGrow, NOT kHasHorzScroll, kHasVertScroll);
- IF FailLowMemory (0) THEN
- HandleError (rMemErrMessages, kMemErrProcListOpenMsg);
-
- (* Make sure the list is activated *)
- LActivate (kActivateList, processList);
-
- (* Save a handle to the list in the refCon of the window *)
- SetWRefCon (aWindow, LongInt (processList));
-
- (* Set the new window as the current GrafPort and return *)
- SetPort (aWindow);
- CreateProcessListWindow := aWindow
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Private: EqualPSN - List Manager search proc
- *
- * The List Manager’s LSearch function can take a pointer to a routine that
- * checks to see if a record matches an entry in the list. The routine must have
- * an interface identical to IUMagIDString. EqualPSN is the routine that I pass
- * to LSearch in the IdleProcessListWindow routine. It compares the process
- * serial number passed in testPSN against the process serial number contained in
- * the ProcessListInfoRec of a cell. Because I already know the lengths of
- * ProcessListInfoRecs and ProcessSerialNumber records, I ignore the aLen and
- * bLen parameters.
- *
- * If the two process serial numbers refer to the same process, then EqualPSN
- * returns 0, otherwise it returns 1.
- *******************************************************************************)
-
- FUNCTION EqualPSN (processInfo: ProcessListInfoPtr;
- testPSN: ProcessSerialNumberPtr;
- aLen: Integer;
- bLen: Integer): Integer;
-
- VAR
- equal: Boolean; {TRUE if PSNs are equal}
- error: OSErr;
-
- BEGIN
- error := SameProcess (testPSN^, processInfo^.serialNumber, (*<*)equal);
- IF equal THEN
- EqualPSN := 0
- ELSE
- EqualPSN := 1
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Private: SetProcessListInfo - Set process list cell info
- *
- * SetProcessListInfo sets the cell specified by row (I’m only using one column,
- * so only the row matters) of the list specified by procList to the information
- * in procInfo. My lists contain ProcessListInfoRecs, which contain only two of
- * the fields in ProcessInfoRecs (process name and process serial number), so I
- * just copy these two fields from procInfo into listInfo. I then use LSetCell
- * to copy listInfo into the list.
- *******************************************************************************)
-
- PROCEDURE SetProcessListInfo (procInfo: ProcessInfoRec;
- row: Integer;
- procList: ListHandle);
-
- VAR
- listInfo: ProcessListInfoRec; {Process info from List Mgr list}
- newCell: Cell; {Cell in which to set information}
- result: Integer; {Result of alert; ignored}
-
- BEGIN
- (* Copy the process name *)
- BlockMove (Ptr(procInfo.processName), @listInfo.processName,
- ORD (procInfo.processName^ [0]) + 1);
-
- (* Copy the process serial number *)
- listInfo.serialNumber := procInfo.processNumber;
-
- (* Set the specified cell to the new ProcessListInfoRec *)
- newCell.h := 0;
- newCell.v := row;
- LSetCell (Ptr(@listInfo), SIZEOF (ProcessListInfoRec), newCell, procList)
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: IdleProcessListWindow
- *
- * I’m using a simple algorithm to keep the process list window’s process list
- * updated to the Process Manager’s process list, but it’ll probably be tough to
- * describe. Here goes. . .
- *
- * I compare the process serial number of each entry in the Process Manager’s
- * list against the process serial number of the corresponding entry in
- * the process list window’s list. If they match, then I just go on to the next
- * entries of the lists. If they don’t match, then I search the window’s list in
- * case the matching process is farther down. If I do find it farther down, then
- * I assume that the processes in the window’s list that come between the
- * matching entries in the two lists were deleted. So, I delete those rows. If
- * I don’t find it farther down, then I assume that the entry is new. I then
- * insert a new row in the corresponding position of the window’s list and copy
- * the process information to it.
- *
- * If I run out of rows in the window’s list before getting through the entire
- * Process Manager list, then I just keep adding new rows to the end of the
- * window’s list and copying over the balance.
- *
- * If I go through the entire Process Manager list but there are left-over
- * entries in the window’s list, then I just delete those left-overs.
- *
- * So, that’s the algorithm. It was the most efficient one I could come up with
- * that wasn’t even harder to explain. Beware: some parts of this routine have
- * only gotten minimal testing, so I wouldn’t be surprised if you find bugs.
- *******************************************************************************)
-
- PROCEDURE IdleProcessListWindow (processListWindow: WindowPtr);
-
- VAR
- procNum: ProcessSerialNumber; {Serial number of open processes}
- procInfo: ProcessInfoRec; {Process info from Proc Mgr list}
- procName: Str31; {Name of the process}
- listInfo: ProcessListInfoRec; {Process info from List Mgr list}
- listInfoLength: Integer; {Size of ProcessListInfoRec}
- currCell: Cell; {List cell being checked}
- matchCell: Cell; {Cell with matching PSN}
- procList: ListHandle; {Handle to List Mgr process list}
- foundMatch: Boolean; {Found matching List Mgr entry}
- equal: Boolean; {Proc and List Mgr elements match}
- result: Integer; {Result of alert; ignored}
- addedProcess: Boolean; {TRUE if a process added to list}
- error: OSErr;
-
- BEGIN
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon (processListWindow));
-
- (* Start checking from start of List Mgr and Process Mgr lists *)
- addedProcess := FALSE;
- currCell.v := 0;
- currCell.h := 0;
- procNum.highLongOfPSN := 0;
- procNum.lowLongOfPSN := kNoProcess;
-
- (* Keep looping through each open process *)
- WHILE GetNextProcess ((*◊*)procNum) = noErr DO
- BEGIN
- (* Get information about an open process *)
- procInfo.processInfoLength := SIZEOF (ProcessInfoRec);
- procInfo.processName := @procName;
- procInfo.processAppSpec := NIL;
- error := GetProcessInformation (procNum, (*◊*)procInfo);
-
- (* Cmp List Mgr & Proc Mgr lists if enuf cells for # of processes *)
- IF PtInRect (currCell, procList^^.dataBounds) THEN
- BEGIN
- (* Get process info from List Mgr list *)
- listInfoLength := SIZEOF (ProcessListInfoRec);
- LGetCell ((*<*)@listInfo, (*◊*)listInfoLength, currCell,
- procList);
-
- (* If Proc & List Mgr lists differ, update List Mgr list *)
- error := SameProcess (procInfo.processNumber, listInfo.
- serialNumber, (*<*)equal);
- IF NOT equal THEN
- BEGIN
- (* See if matching process farther down List Mgr list *)
- matchCell := currCell;
- foundMatch := LSearch (@procInfo.processNumber,
- SIZEOF (ProcessSerialNumber), @EqualPSN,
- (*◊*)matchCell, procList);
-
- (* Was there a match farther down the List Mgr list? *)
- IF foundMatch THEN
- (* Yes, delete intervening cells *)
- LDelRow (matchCell.v - currCell.v, currCell.v,
- procList)
- ELSE
- (* No, insert the new process into List Mgr list *)
- BEGIN
- currCell.v := LAddRow (1, currCell.v, procList);
- SetProcessListInfo (procInfo, currCell.v,
- procList)
- END
- END
- END
- ELSE
- BEGIN
- (* Ran out of rows, add one *)
- currCell.v := LAddRow (1, currCell.v, procList);
- addedProcess := TRUE;
-
- (* Set the new row to the new process information *)
- SetProcessListInfo (procInfo, currCell.v, procList)
- END;
-
- (* Go to the next cell element in List Mgr list *)
- currCell.v := SUCC (currCell.v)
- END;
-
- (* Delete any extraneous cells *)
- IF currCell.v < procList^^.dataBounds.bottom THEN
- LDelRow (procList^^.dataBounds.bottom - currCell.v, currCell.v,
- procList);
-
- (* If added processes to the list and memory low, warn *)
- IF addedProcess AND FailLowMemory (0) THEN
- result := ShowCautionOKAlert (rMemErrMessages, kMemErrLowMemWarnMsg)
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: DrawProcessListWindow
- *
- * Not much here to explain.
- *******************************************************************************)
-
- PROCEDURE DrawProcessListWindow (processListWindow: WindowPtr);
-
- VAR
- procList: ListHandle; {Handle to List Mgr process list}
-
- BEGIN
- SetPort (processListWindow);
-
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon (processListWindow));
-
- (* Update the list *)
- TextFont (1);
- TextFace ([]);
- TextSize (GetDefFontSize);
- EraseRect (processListWindow^.portRect);
- LUpdate (processListWindow^.visRgn, procList);
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: ClickProcessListWindow
- *
- * The List Manager is doing the lion’s share of the work.
- *******************************************************************************)
-
- PROCEDURE ClickProcessListWindow (processListWindow: WindowPtr;
- clickEvent: EventRecord);
-
- VAR
- procList: ListHandle; {Handle to List Mgr process list}
- clickPos: Point; {Position of mouse click in window coords}
- doubleClick: Boolean; {TRUE if cell was double-clicked}
-
- BEGIN
- SetPort (processListWindow);
-
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon (processListWindow));
-
- (* Call the List Manager to handle the click *)
- clickPos := clickEvent.where;
- GlobalToLocal ((*◊*)clickPos);
- doubleClick := LClick (clickPos, clickEvent.modifiers, procList);
- IF doubleClick THEN
- DoBringProcessToFront (processListWindow);
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: ActivateProcessListWindow
- *
- * The List Manager is called to activate/deactivate the process list window.
- *******************************************************************************)
-
- PROCEDURE ActivateProcessListWindow (processListWindow: WindowPtr;
- becomingActive: Boolean);
-
- VAR
- procList: ListHandle; {Handle to List Mgr process list}
-
- BEGIN
- SetPort (processListWindow);
-
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon (processListWindow));
-
- (* Call the List Manager to activate or deactivate the list *)
- LActivate (becomingActive, procList)
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: FixProcessListMenus
- *
- * The three launching items in the File menu are enabled as long as there’s
- * enough memory available.
- *
- * The List Manager routine, LGetSelect, is called to see if there are any
- * processes in the Process List window specified by the "processListWindow"
- * parameter that are selected. If there are, then the three items in the
- * Process menu are enabled. If there isn’t enough memory to safely work in,
- * then only the Bring Process to Front is enabled.
- *******************************************************************************)
-
- PROCEDURE FixProcessListMenus (processListWindow: WindowPtr);
-
- CONST
- kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
-
- VAR
- aMenu: MenuHandle; {Handle to any menu we’re checking on}
- procList: ListHandle; {Handle to List Mgr process list}
- aCell: Cell; {Cell of process list}
-
- BEGIN
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon (processListWindow));
-
- (* Enable the File menu launch items *)
- aMenu := GetMHandle (mFile);
- IF NOT FailLowMemory (0) THEN
- BEGIN
- EnableItem (aMenu, iLaunchFore);
- EnableItem (aMenu, iLaunchBack);
- EnableItem (aMenu, iLaunchTo)
- END;
-
- (* Undim the Process menu items *)
- aMenu := GetMHandle (mProcess);
- aCell.v := 0;
- aCell.h := 0;
- IF LGetSelect (kFindNext, (*◊*)aCell, procList) THEN
- BEGIN
- (* There’s ≥ 1 sel’d process, enable Bring Process to Front *)
- EnableItem (aMenu, iBringFront);
-
- (* Only enable other two items if enough memory to safely work *)
- IF NOT FailLowMemory (0) THEN
- BEGIN
- EnableItem (aMenu, iShowProcessInfo);
- EnableItem (aMenu, iTerminateProcess)
- END
- END
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Public: IsProcessInfoWindow
- *
- * I store a unique code in the windowKind field of every window I create so that
- * I can identify the kind of window it is later… like now! I check to see if
- * the windowKind field of aWindow is kProcessInfoWindKind or not. If it is, I
- * know it’s a process info window, and so IsProcessInfoWindow returns TRUE.
- *******************************************************************************)
-
- FUNCTION IsProcessInfoWindow (aWindow: WindowPtr): Boolean;
-
- BEGIN
- IF aWindow <> NIL THEN
- IsProcessInfoWindow := WindowPeek(aWindow)^.windowKind =
- kProcessInfoWindKind
- ELSE
- IsProcessInfoWindow := FALSE
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Private: GetNumberParts - Get the default number parts table
- *
- * To use the Script Manager’s number conversion routines, the number parts table
- * in the 'itl4' resource must be retrieved. This routine gets the itl4 resource
- * and copies the number parts table into the "partsTable" parameter.
- *
- * If the retrieval was successful, then TRUE is returned. If the itl4 resource
- * couldn’t be loaded for some reason, then FALSE is returned.
- *******************************************************************************)
-
- FUNCTION GetNumberParts (VAR partsTable: NumberParts): Boolean;
-
- VAR
- intl4: Itl4Handle; {Handle to the itl4 resource}
-
- BEGIN
- intl4 := Itl4Handle(IUGetIntl (4));
- IF intl4 <> NIL THEN
- BEGIN
- partsTable := NumberPartsPtr(ORD (intl4^) + intl4^^.
- defPartsOffset)^;
- GetNumberParts := TRUE
- END
- ELSE
- GetNumberParts := FALSE
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Private: TextLineBox - Draw a line of text into a box.
- *
- * This routine is very similar to TextEdit’s TextBox routine, and in fact it
- * takes the same parameters. But TextLineBox draws a single line of text
- * specified by "textLine" and having the length specified by "length" into
- * the current GrafPort, ignoring carriage returns and word-wrap. This means
- * that there’s less overhead than TextBox. But TextBox itself is optimized for
- * single lines of text, so there is an ulterior motive for this routine.
- * TextBox erases the entire box before drawing the text. This results in a
- * slight flicker if TextBox is called to draw over previous text. TextLineBox
- * only erases the part of the box that isn’t covered with the text specified by
- * "textLine". Also, the text is drawn in srcCopy mode. If TextLineBox is
- * called to draw over existing text, the result should be a smooth transition
- * from one text to another, without flicker.
- *******************************************************************************)
-
- PROCEDURE TextLineBox (textLine: Ptr;
- length: Integer;
- box: Rect;
- just: Integer);
-
- VAR
- currPort: GrafPtr; {Pointer to the current GrafPort}
- currTextMode: Integer; {Current text mode}
- currFont: FontInfo; {Current font information}
- lineWidth: Integer; {Width of line of text in pixels}
- spareSpace: Integer; {Width of box - width of text}
- spareRect: Rect; {Rectangle of area not filled with text}
- currClip: RgnHandle; {Handle to the current clip region}
-
- BEGIN
- (* Save the current clip region and set the clip region to "box" *)
- currClip := NewRgn;
- GetClip ((*<*)currClip);
- ClipRect (box);
-
- (* Save the current text mode and set it to srcCopy *)
- GetPort ((*<*)currPort);
- currTextMode := currPort^.txMode;
- TextMode (srcCopy);
-
- (* If default justification, set to real justification based on SysJust *)
- IF just = teFlushDefault THEN
- IF GetSysJust = 0 THEN
- just := teFlushLeft
- ELSE
- just := teFlushRight;
-
- (* Move pen to baseline on left side of box *)
- GetFontInfo (currFont);
- MoveTo (box.left, box.top + currFont.ascent);
-
- (* Find the width of the specified text *)
- lineWidth := TextWidth (textLine, 0, length);
-
- (* Adjust the pen for centered or right-aligned text *)
- IF just <> teFlushLeft THEN
- BEGIN
- spareSpace := box.right - box.left - lineWidth;
- IF just = teCenter THEN
- spareSpace := spareSpace DIV 2;
- Move (spareSpace, 0);
- END;
-
- (* Erase area at end(s) of text *)
- spareRect := box;
- IF just = teFlushLeft THEN
- spareRect.left := spareRect.left + lineWidth
- ELSE
- BEGIN
- IF just = teCenter THEN
- BEGIN
- spareRect.left := spareRect.left + spareSpace + lineWidth;
- EraseRect (spareRect)
- END;
- spareRect.left := box.left;
- spareRect.right := spareRect.left + spareSpace;
- END;
- IF NOT EmptyRect (spareRect) THEN
- EraseRect (spareRect);
-
- (* Draw the line of text *)
- DrawText (textLine, 0, length);
-
- (* Restore the port to its normal state *)
- TextMode (currTextMode);
- SetClip (currClip);
- DisposeRgn (currClip)
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Private: FindProcessInfoWindow - Find a process info window for a process
- *
- * This routine searches the window list for a process info window that
- * represents the process with the process serial number specified by
- * "searchPSN". Every process info window has a handle to the process serial
- * number of the process it represents in the refCon field of the window. The
- * Process Manager routine, SameProcess, does the work of comparing the given
- * process serial number against the process serial number in the refCon.
- *
- * If a window for the specified process is found, a pointer to that window is
- * returned. If there isn’t any window representing the given process, then NIL
- * is returned.
- *******************************************************************************)
-
- FUNCTION FindProcessInfoWindow (searchPSN: ProcessSerialNumber): WindowPtr;
-
- VAR
- testWindow: WindowPtr; {Pointer to window we’re testing}
- found: Boolean; {TRUE if matching process info window was found}
- psnHandle: Handle; {Handle to PSN of window’s process info window}
- error: OSErr;
-
- BEGIN
- found := FALSE;
- testWindow := FrontWindow;
-
- (* Loop until the window is found or every window has been searched *)
- WHILE (testWindow <> NIL) AND (NOT found) DO
- BEGIN
- IF IsProcessInfoWindow (testWindow) THEN
- BEGIN
- (* Get the PSN of the window from its refCon *)
- psnHandle := Handle(GetWRefCon (testWindow));
-
- (* Compare window’s PSN against searchPSN *)
- HLock (psnHandle);
- error := SameProcess (searchPSN, PSNPtr(psnHandle^)^,
- (*<*)found);
- HUnlock (psnHandle)
- END;
-
- (* Go to the next window in the window list *)
- IF NOT found THEN
- testWindow := WindowPtr(WindowPeek(testWindow)^.nextWindow)
- END;
-
- (* Return pointer to matching process info window, or NIL if no match *)
- FindProcessInfoWindow := testWindow
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Private: CreateProcessInfoWindow - Create a process info window
- *
- * This routine is called to create a new process info window and to display it
- * on the screen. A pointer to the window is returned. If there wasn’t enough
- * memory to open the new window, or if there was some other problem preventing
- * the window from being completely created, then an alert indicating the problem
- * is presented to the user and NIL is returned.
- *
- * I store the constant kProcessInfoWindKind into the windowKind field of the new
- * window. When the routine IsProcessInfoWindow is called, it uses this field to
- * identify a window as a process info window.
- *******************************************************************************)
-
- FUNCTION CreateProcessInfoWindow: WindowPtr;
-
- VAR
- aWindow: WindowPtr; {Pointer to the new window}
- error: OSErr;
-
- PROCEDURE HandleError (messageClass: Integer;
- messageIndex: Integer);
-
- VAR
- result: Integer; {Result of alert; ignored}
-
- BEGIN
- IF aWindow <> NIL THEN
- CloseProcessInfoWindow (aWindow);
- result := ShowStopAlert (messageClass, messageIndex);
- gError := noErr;
- CreateProcessInfoWindow := NIL;
- EXIT (CreateProcessInfoWindow)
- END;
-
- BEGIN
- aWindow := NIL;
-
- (* Create the new window *)
- aWindow := CreateDialog (rProcessInfoWindID);
- IF aWindow = NIL THEN
- IF gError = memFullErr THEN
- HandleError (rMemErrMessages, kMemErrProcInfoOpenMsg)
- ELSE IF gError = resNotFound THEN
- HandleError (rResErrMessages, kResErrAppDamageMsg)
- ELSE IF gError = dsSysErr THEN
- HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
-
- (* Set up the window *)
- SetPort (aWindow);
- WindowPeek(aWindow)^.windowKind := kProcessInfoWindKind;
-
- (* Install the dialog items *)
- error := InstallDialogItems (aWindow, rProcessInfoDitlID);
- IF error <> noErr THEN
- IF error = memFullErr THEN
- HandleError (rMemErrMessages, kMemErrProcInfoOpenMsg)
- ELSE IF error = resNotFound THEN
- HandleError (rResErrMessages, kResErrAppDamageMsg)
- ELSE IF error = dsSysErr THEN
- HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
-
- CreateProcessInfoWindow := aWindow
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Private: DrawGrayLine - Draw a gray line into a dialog item
- *
- * DrawGrayLine draws a line from the top-left corner of "grayLineRect" to its
- * bottom-right corner. On a non-Color QuickDraw Macintosh, this line is simply
- * drawn using the 50% gray pattern. On a Color QuickDraw Macintosh, a gray
- * type-2 pattern is created with a gray color. When this pattern is used to
- * draw to the screen, it is drawn using the specified color if possible. If
- * there aren’t enough available colors, the color is dithered using the closest
- * available colors.
- *******************************************************************************)
-
- PROCEDURE DrawGrayLine (grayLineRect: Rect);
-
- VAR
- qdVersion: LongInt; {QuickDraw version number}
- grayColor: RGBColor; {Color of gray line}
- grayPattern: PixPatHandle; {Handle to the gray pattern}
- result: OSErr;
-
- BEGIN
- grayPattern := NIL;
- PenNormal;
-
- (* See if Color QuickDraw is on this machine or not *)
- result := Gestalt (gestaltQuickdrawVersion, (*<*)qdVersion);
- IF qdVersion = gestaltOriginalQD THEN
- (* Nope, just draw a 50% gray pattern *)
- PenPat (gray)
- ELSE
- (* Yup, make a true gray pattern that can be dithered to the screen *)
- BEGIN
- grayColor.red := $7FFF;
- grayColor.green := $7FFF;
- grayColor.blue := $7FFF;
- grayPattern := NewPixPat;
- MakeRGBPat (grayPattern, grayColor);
- PenPixPat (grayPattern);
- END;
-
- (* Draw the line *)
- MoveTo (grayLineRect.left, grayLineRect.top);
- LineTo (grayLineRect.right, grayLineRect.bottom);
-
- (* Clean up *)
- IF grayPattern <> NIL THEN
- DisposPixPat (grayPattern);
- PenNormal
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Private: SetUpProcessInfoItems - Set up process information static text items
- *
- * This routine sets up the text of the static text items in the process info
- * window specified by "processInfoWindow" to reflect the process information
- * passed in the "processInfo" parameter. Only the process information that
- * doesn’t change while a process is active is set in this routine. Information
- * that changes while a process is active is set and drawn in the
- * IdleProcessInfoWindow routine.
- *
- * Numbers are converted to strings using the FormatX2Str routine. FormatX2Str
- * requires a script-independent canonical number format so that the resulting
- * string appears with the proper thousands separator regardless of the script
- * in use. I previously created a canonical number format that has the form
- * ###,###,### in the U.S and saved it in a resource of type NUMF.
- *******************************************************************************)
-
- PROCEDURE SetUpProcessInfoItems (processInfoWindow: WindowPtr;
- processInfo: ProcessInfoRec);
-
- VAR
- itemString: Str255; {"Application" or "Desk Accessory" string}
- blankString: Integer; {Dummy empty string}
- checkString: StringPtr; {Ptr either to check mark or blankString}
- checkStrHnd: StringHandle; {Handle to check mark string}
- partitionSize: extended; {Size of processes partition}
- partsTable: NumberParts; {Number parts table from itl4 resource}
- canonRsrc: Handle; {Hnd to canonical # format '###,###,###'}
- status: FormatStatus; {Status of #->String conversion}
- success: Boolean; {TRUE if GetNumberParts call worked}
-
- BEGIN
- (* Set process name *)
- SetStatTextItem (processInfoWindow, kProcessNameItem, @processInfo.
- processName^ [1], ORD (processInfo.processName^ [0]));
-
- (* Set Application or Desk Accessory string *)
- IF BAND (processInfo.processMode, modeDeskAccessory) <> 0 THEN
- GetIndString ((*◊*)itemString, rAppOrDAStringID, kDAStringInd)
- ELSE
- GetIndString ((*◊*)itemString, rAppOrDAStringID, kAppStringInd);
- SetStatTextItem (processInfoWindow, kAppOrDAItem, @itemString [1],
- ORD (itemString [0]));
-
- (* Set partition size item *)
- partitionSize := processInfo.processSize DIV 1024;
- success := GetNumberParts (partsTable);
- IF success THEN
- BEGIN
- (* Get the canonical number format I created earlier *)
- canonRsrc := Get1Resource ('NUMF', 0);
- IF canonRsrc <> NIL THEN
- BEGIN
- (* Convert partition size from extended to formatted string *)
- HLock (canonRsrc);
- status := FormatX2Str (partitionSize,
- NumFormatStringPtr(canonRsrc^)^, partsTable,
- (*<*)itemString);
- HUnlock (canonRsrc);
-
- (* Set Total Size item to formatted partition size string *)
- SetStatTextItem (processInfoWindow, kTotalSizeItem,
- @itemString [1], ORD (itemString [0]))
- END
- END;
-
- (* Set type and creator *)
- SetStatTextItem (processInfoWindow, kTypeItem, @processInfo.processType,
- SIZEOF (LongInt));
- SetStatTextItem (processInfoWindow, kCreatorItem, @processInfo.
- processSignature, SIZEOF (OSType));
-
- (* Initialize the checkmark and blank strings *)
- checkStrHnd := GetString (rCheckMarkID);
- IF checkStrHnd <> NIL THEN
- BlockMove (Ptr(checkStrHnd^), @itemString, ORD (checkStrHnd^^ [0]) + 1)
- ELSE
- itemString [0] := CHR (0);
- blankString := 0;
-
- (* Check the suspend/resume flag *)
- IF BAND (processInfo.processMode, modeNeedSuspendResume) <> 0 THEN
- checkString := @itemString
- ELSE
- checkString := @blankString;
- SetStatTextItem (processInfoWindow, kSusResChkItem, @checkString^ [1],
- ORD (checkString^ [0]));
-
- (* Check the window activate flag *)
- IF BAND (processInfo.processMode, modeDoesActivateOnFGSwitch) <> 0 THEN
- checkString := @itemString
- ELSE
- checkString := @blankString;
- SetStatTextItem (processInfoWindow, kWindActChkItem, @checkString^ [1],
- ORD (checkString^ [0]));
-
- (* Check the window activate flag *)
- IF BAND (processInfo.processMode, modeGetFrontClicks) <> 0 THEN
- checkString := @itemString
- ELSE
- checkString := @blankString;
- SetStatTextItem (processInfoWindow, kGetClickChkItem, @checkString^ [1],
- ORD (checkString^ [0]));
-
- (* Check the window activate flag *)
- IF BAND (processInfo.processMode, modeGetAppDiedMsg) <> 0 THEN
- checkString := @itemString
- ELSE
- checkString := @blankString;
- SetStatTextItem (processInfoWindow, kAppDiedChkItem, @checkString^ [1],
- ORD (checkString^ [0]));
-
- (* Check the window activate flag *)
- IF BAND (processInfo.processMode, modeStationeryAware) <> 0 THEN
- checkString := @itemString
- ELSE
- checkString := @blankString;
- SetStatTextItem (processInfoWindow, kStationeryChkItem, @checkString^ [1],
- ORD (checkString^ [0]));
-
- (* Check the window activate flag *)
- IF BAND (processInfo.processMode, modeCanBackground) <> 0 THEN
- checkString := @itemString
- ELSE
- checkString := @blankString;
- SetStatTextItem (processInfoWindow, kCanBackChkItem, @checkString^ [1],
- ORD (checkString^ [0]));
-
- (* Check the window activate flag *)
- IF BAND (processInfo.processMode, modeOnlyBackground) <> 0 THEN
- checkString := @itemString
- ELSE
- checkString := @blankString;
- SetStatTextItem (processInfoWindow, kOnlyBackChkItem, @checkString^ [1],
- ORD (checkString^ [0]));
-
- (* Check the window activate flag *)
- IF BAND (processInfo.processMode, modeHighLevelEventAware) <> 0 THEN
- checkString := @itemString
- ELSE
- checkString := @blankString;
- SetStatTextItem (processInfoWindow, kHighLevelChkItem, @checkString^ [1],
- ORD (checkString^ [0]));
-
- (* Check the window activate flag *)
- IF BAND (processInfo.processMode, modeLocalAndRemoteHLEvents) <> 0 THEN
- checkString := @itemString
- ELSE
- checkString := @blankString;
- SetStatTextItem (processInfoWindow, kRHighLevelChkItem, @checkString^ [1],
- ORD (checkString^ [0]));
-
- (* Check the window activate flag *)
- IF BAND (processInfo.processMode, modeMultiLaunch) <> 0 THEN
- checkString := @itemString
- ELSE
- checkString := @blankString;
- SetStatTextItem (processInfoWindow, kMultiUserChkItem, @checkString^ [1],
- ORD (checkString^ [0]));
-
- (* Check the window activate flag *)
- IF BAND (processInfo.processMode, mode32BitCompatible) <> 0 THEN
- checkString := @itemString
- ELSE
- checkString := @blankString;
- SetStatTextItem (processInfoWindow, k32BitCleanChkItem, @checkString^ [1],
- ORD (checkString^ [0]));
-
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: IdleProcessInfoWindow
- *
- * The memory indicator and the free memory readout are updated with the current
- * values.
- *
- * The free memory readout is a static text item in the DITL, but there’s no text
- * for it. Instead, I’m drawing into that item’s rectangle using TextLineBox.
- * I set the item up as a static text item just so that I can specify the type
- * characteristics of the free memory readout from the DITL resource rather than
- * hard-coding them in this routine.
- *
- * Numbers are converted to strings using the FormatX2Str routine. FormatX2Str
- * requires a script-independent canonical number format so that the resulting
- * string appears with the proper thousands separator regardless of the script
- * in use. I previously created a canonical number format that has the form
- * ###,###,### in the U.S and saved it in a resource of type NUMF.
- *******************************************************************************)
-
- PROCEDURE IdleProcessInfoWindow (processInfoWindow: WindowPtr);
-
- VAR
- processInfo: ProcessInfoRec; {Process info for window’s process}
- psnHandle: Handle; {Handle to PSN of window’s process}
- freeSpace: extended; {Amount of free space in partition}
- canonRsrc: Handle; {canonical # format '###,###,###'}
- freeSpaceStr: Str255; {String representation of freeSpace}
- status: FormatStatus; {Status of #->string conversion}
- partsTable: NumberParts; {Number parts table from itl4 resource}
- itemType: TypeInfoRec; {Type information for free mem readout}
- itemRect: Rect; {Rectangle of dialog item}
- freeAngle: Integer; {Angle between free and full memory}
- aColor: RGBColor; {Color to draw memory indicator}
- qdVersion: LongInt; {Version of QuickDraw on this machine}
- success: Boolean; {TRUE if GetNumberParts call worked}
- error: OSErr;
-
- BEGIN
- SetPort (processInfoWindow);
- PenNormal;
-
- (* Get the PSN of the process associated with processInfoWindow *)
- psnHandle := Handle(GetWRefCon (processInfoWindow));
-
- (* Get information about an open process *)
- processInfo.processInfoLength := SIZEOF (ProcessInfoRec);
- processInfo.processName := NIL;
- processInfo.processAppSpec := NIL;
- HLock (psnHandle);
- error := GetProcessInformation (PSNPtr(psnHandle^)^, (*◊*)processInfo);
- HUnlock (psnHandle);
-
- (* Check to see whether the process still exists *)
- IF error = procNotFound THEN
- (* Process terminated, so close this process info window *)
- CloseProcessInfoWindow (processInfoWindow)
- ELSE
- BEGIN
- (* Starting here, convert amount of free space to a string *)
- freeSpace := processInfo.processFreeMem DIV 1024;
-
- (* Get number parts table from itl4 *)
- success := GetNumberParts ((*<*)partsTable);
- IF success THEN
- BEGIN
- (* Get my canonical number format *)
- canonRsrc := Get1Resource ('NUMF', 0);
- IF canonRsrc <> NIL THEN
- BEGIN
- (* Convert free space to equivalent string *)
- HLock (canonRsrc);
- status := FormatX2Str (freeSpace,
- NumFormatStringPtr(canonRsrc^)^, partsTable,
- (*<*)freeSpaceStr);
- HUnlock (canonRsrc);
-
- (* Get the item rectangle of the free-space readout *)
- GetDialogItemRect (processInfoWindow, kFreeSpaceItem,
- (*<*)itemRect);
-
- (* Get the font characteristics of the stat text item *)
- GetStatTextFontInfo (processInfoWindow, kFreeSpaceItem,
- (*<*)itemType);
-
- (* Draw the free-space readout *)
- TextFont (itemType.typeFace);
- TextSize (itemType.typeSize);
- TextFace (itemType.typeStyle);
- TextLineBox (@freeSpaceStr [1], ORD (freeSpaceStr [0]),
- itemRect, itemType.textJust)
- END;
- END;
-
- (* Draw the memory indicator frame *)
- GetDialogItemRect (processInfoWindow, kMemIndicatorItem,
- (*<*)itemRect);
- FrameOval (itemRect);
- InsetRect ((*◊*)itemRect, 1, 1);
-
- (* Calc angle in the memory indicator that the free memory begins *)
- freeAngle := processInfo.processFreeMem * 360 DIV processInfo.
- processSize;
-
- (* Draw the memory indicator *)
- error := Gestalt (gestaltQuickdrawVersion, (*<*)qdVersion);
- IF qdVersion = gestaltOriginalQD THEN
- PenPat (black)
- ELSE
- BEGIN
- PmForeColor (kUsedColor);
- PmBackColor (0)
- END;
-
- (* Draw the used memory part of the memory indicator *)
- PaintArc (itemRect, 0, 360 - freeAngle);
-
- (* Set the color of the free memory part of the indicator *)
- IF qdVersion = gestaltOriginalQD THEN
- PenPat (white)
- ELSE
- BEGIN
- PmForeColor (kFreeColor);
- PmBackColor (1)
- END;
-
- (* Draw the free memory part of the memory indicator *)
- PaintArc (itemRect, 360 - freeAngle, freeAngle);
-
- (* Reset the port characteristics back to normal *)
- PenNormal;
- IF qdVersion <> gestaltOriginalQD THEN
- BEGIN
- PmForeColor (1);
- PmBackColor (0)
- END
- END
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: DrawProcessInfoWindow
- *
- * The Dialog Utility routine, DrawDialogItems, is called to draw all the
- * standard dialog items in the processInfoWindow specified by processInfoWindow.
- * Then, the cosmetic gray lines are drawn. The memory readouts aren’t drawn
- * because they’re drawn in IdleProcessInfoWindow.
- *******************************************************************************)
-
- PROCEDURE DrawProcessInfoWindow (processInfoWindow: WindowPtr);
-
- VAR
- grayLineRect: Rect; {Rectangle of gray line item}
-
- BEGIN
- (* Draw the standard dialog items *)
- DrawDialogItems (processInfoWindow);
-
- (* Draw the two gray, cosmetic, separating lines *)
- GetDialogItemRect (processInfoWindow, kGrayLineItem0, (*<*)grayLineRect);
- DrawGrayLine (grayLineRect);
- GetDialogItemRect (processInfoWindow, kGrayLineItem1, (*<*)grayLineRect);
- DrawGrayLine (grayLineRect)
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: FixProcessInfoMenus
- *
- * If there’s enough memory to work with, the launch items in the File menu are
- * enabled.
- *******************************************************************************)
-
- PROCEDURE FixProcessInfoMenus (processInfoWindow: WindowPtr);
-
- VAR
- aMenu: MenuHandle; {Handle to any menu we’re checking on}
-
- BEGIN
- (* Undim the File menu items *)
- aMenu := GetMHandle (mFile);
- IF NOT FailLowMemory (0) THEN
- BEGIN
- EnableItem (aMenu, iLaunchFore);
- EnableItem (aMenu, iLaunchBack);
- EnableItem (aMenu, iLaunchTo)
- END
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: CloseProcessInfoWindow
- *
- * This should be pretty easy to figure out.
- *******************************************************************************)
-
- PROCEDURE CloseProcessInfoWindow (processInfoWindow: WindowPtr);
-
- VAR
- psnHandle: Handle; {Handle to the PSN of process the window represents}
-
- BEGIN
- DisposHandle (Handle(GetWRefCon (processInfoWindow)));
- CloseWindow (processInfoWindow);
- DisposeDialogItems (processInfoWindow);
- DisposPtr (Ptr(processInfoWindow))
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: IdleAllProcessWindows
- *
- * The process list window and process info windows each have their own idle
- * routine defined in this source file, so the type of window is checked and the
- * appropriate idle routine is called for that window.
- *******************************************************************************)
-
- PROCEDURE IdleAllProcessWindows;
-
- VAR
- processWindow: WindowPtr; {Pointer to each process window being idled}
-
- BEGIN
- processWindow := FrontWindow;
-
- (* Loop through all windows in the window list *)
- WHILE processWindow <> NIL DO
- BEGIN
- (* Call the appropriate idle routine if it’s a process window *)
- IF IsProcessListWindow (processWindow) THEN
- IdleProcessListWindow (processWindow)
- ELSE IF IsProcessInfoWindow (processWindow) THEN
- IdleProcessInfoWindow (processWindow);
-
- (* Go to the next window in the window list *)
- processWindow := WindowPtr(WindowPeek(processWindow)^.nextWindow)
- END
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Private: AppDAFilter - File filter procedure for apps and files with DAs
- *
- * This is a Standard File file filter procedure that allows applications and
- * any files with desk accessories in them to show up in the Standard File file
- * list.
- *
- * Checking to see whether a file is an application is easy enough. Just
- * check to see whether its type is APPL. If it is, then it’s an application.
- * Checking on desk accessories is trickier. Desk accessories can be contained
- * in any type of file. So if a file isn’t doesn’t have the APPL type, I open
- * the resource fork of the file using HOpenResFile and an access mode of
- * fdRdPerm. This allows me to open and close the resource file without worrying
- * about that resource file being open by someone else because HOpenResFile with
- * an access mode of fdRdPerm returns a unique access path to this routine. When
- * the file is open, I check for DRVR resources. DRVR resources can be either
- * desk accessories or device drivers. I only want to show files containing desk
- * accessories, so I check on the first character of the DRVR resource’s name.
- * If it’s a null character, then the DRVR is a desk accessory. If it’s any
- * other character, then it’s a device driver and I ignore it.
- *******************************************************************************)
-
- FUNCTION AppDAFilter (fileInfo: CInfoPBPtr): Boolean;
-
- CONST
- kShowIt = FALSE; {FALSE means I do not filter out...}
-
- TYPE
- LongIntPtr = ^LongInt;
-
- VAR
- resRef: Integer; {File ref num of file being tested}
- currResRef: Integer; {File ref number of current file}
- numDrvrs: Integer; {Number of DRVR resources in file being tested}
- index: Integer; {Index into resources of file being tested}
- drvrRsrc: Handle; {Handle to DRVR resource; always NIL master ptr}
- resID: Integer; {Resource ID of DRVR resource; ignored}
- resType: ResType; {Resource type of DRVR resource; ignored}
- resName: Str255; {Resource name of DRVR resource}
-
- BEGIN
- IF fileInfo^.ioFlFndrInfo.fdType ='APPL' THEN
- AppDAFilter := kShowIt
- ELSE
- BEGIN
- (* Assume we don’t show the file *)
- AppDAFilter := NOT kShowIt;
-
- (* Want to check rsrcs, not load ’em, including preload resources *)
- SetResLoad (FALSE);
-
- (* Save current res file refnum, open the specified rsrc file *)
- currResRef := CurResFile;
- resRef := HOpenResFile (fileInfo^.ioVRefNum,
- LongIntPtr(CurDirStore)^, fileInfo^.ioNamePtr^, fsRdPerm);
-
- (* If couldn’t open resource file, HOpenResFile returns -1 *)
- IF (resRef <> -1) THEN
- BEGIN
- UseResFile (resRef);
-
- (* Count number of DRVR resources in the file *)
- numDrvrs := Count1Resources ('DRVR');
- IF numDrvrs > 0 THEN
- BEGIN
- (* For each DRVR, see if it’s a DA *)
- FOR index := 1 TO numDrvrs DO
- BEGIN
- drvrRsrc := Get1IndResource ('DRVR', index);
- GetResInfo (drvrRsrc, (*<*)resID, (*<*)resType,
- (*<*)resName);
-
- (* If first char of name is null, it’s a DA *)
- IF resName [1] = CHR (0) THEN
- AppDAFilter := kShowIt
- END
- END;
- CloseResFile (resRef)
- END;
-
- (* Restore everything back to what it was *)
- UseResFile (currResRef);
- SetResLoad (TRUE)
- END
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Private: LaunchCycle - Attempt to launch a process
- *
- * This routine calls the LaunchProcess routine that’s in the UProcessUtils unit.
- * The launchFile parameter specifies the file to launch. The docList parameter
- * specifies the list of documents to pass to the launched application for it to
- * open or print. The launchOptions parameter specifies the initial set of
- * launch options to use when launching. The the section titled “Specifying
- * Launch Options” in the Process Manager chapter of Inside Macintosh VI for the
- * a list and description of the launch options that you can pass in this
- * parameter.
- *
- * If the Process Manager denies the launch, then LaunchProcess returns the
- * resulting error code in the LaunchError flag. If this happens and if the
- * error happened to be that the machine is in 32-bit addressing mode and the
- * application’s SIZE resource doesn’t have the 32-bit clean flag on, or if there
- * isn’t enough memory to launch the application or desk accessory, then an alert
- * is presented to the user asking if he or she wants to continue anyway. If the
- * user specifies that he or she does, then launch options are added to the ones
- * passed in the launchOptions parameter which allow 32-bit unclean applications
- * to launch or to allow the launch into available memory, and then LaunchProcess
- * is called again. This is repeated either until the application or desk
- * accessory is successfully launched, the user chose not to launch it, or until
- * an unrecoverable error occurs.
- *******************************************************************************)
-
- PROCEDURE LaunchCycle (launchFile: FSSpec;
- docList: DocListHnd;
- launchOptions: Integer);
-
- VAR
- processNum: ProcessSerialNumber; {Serial number of launched process}
- attemptLaunch: Boolean; {TRUE if continuing launch attempt}
- result: Integer; {Result of caution alert}
- launchError: OSErr; {Launch error code}
- error: OSErr;
-
- BEGIN
- (* Repeat until successful launch or cancelled launch *)
- REPEAT
- (* Attempt to launch the process *)
- error := LaunchProcess (launchFile, NIL, docList, launchOptions,
- (*<*)processNum, (*<*)launchError);
-
- (* Check for launching errors *)
- IF launchError <> noErr THEN
- BEGIN
- (* There was a launching error, present to user *)
- IF launchError = appModeErr THEN
- BEGIN
- (* Ask user if it’s OK to launch 32-bit unclean app *)
- result := ShowCautionOKCancelAlert (rMiscWrnMessages,
- kMiscWrnUncleanMsg);
- IF result = ok THEN
- BEGIN
- (* Try launch again, allowing 32-bit unclean app *)
- launchOptions := BOR (launchOptions,
- launchAllow24Bit);
- attemptLaunch := TRUE
- END
- ELSE
- attemptLaunch := FALSE
- END
- ELSE IF launchError = memFullErr THEN
- BEGIN
- (* Ask user if it’s OK to launch w/ < requested memory *)
- result := ShowCautionOKCancelAlert (rMiscWrnMessages,
- kMiscWrnLaunchMemMsg);
- IF result = ok THEN
- BEGIN
- (* Try launch again, with less than requested mem *)
- launchOptions := BOR (launchOptions,
- launchUseMinimum);
- attemptLaunch := TRUE
- END
- ELSE
- attemptLaunch := FALSE
- END
- ELSE
- BEGIN
- (* Some error we don’t handle happened *)
- result := ShowStopAlert (rMiscErrMessages,
- kMiscErrUnknownMsg);
- attemptLaunch := FALSE
- END
- END
- ELSE IF error <> noErr THEN
- BEGIN
- result := ShowStopAlert (rMiscErrMessages,
- kMiscErrUnknownMsg);
- attemptLaunch := FALSE
- END
- ELSE
- attemptLaunch := FALSE
- UNTIL NOT attemptLaunch;
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: DoLaunchInFront
- *
- * If the user is launching with documents, then only applications are presented
- * to the user in the standard-file dialog. If the user only wants to launch
- * without any documents, then both applications and files containing desk
- * accessories are presented to the user.
- *******************************************************************************)
-
- PROCEDURE DoLaunchInFront;
-
- VAR
- reply: StandardFileReply; {Reply from SFGetFile}
- typeList: SFTypeList; {List of file types for SF}
- launchSpec: FSSpec; {Location of selected app/DA}
- docList: DocListHnd; {Handle to the document list}
- gettingDocs: Boolean; {True if user still getting docs}
- launchMode: LaunchModeCode; {Current launch mode}
- error: OSErr;
-
- BEGIN
- (* Get the user’s choice for a file to launch *)
- launchMode := GetLaunchMode;
- IF launchMode = kJustLaunch THEN
- (* Just launching, so launch applications and DAs *)
- StandardGetFile (@AppDAFilter, -1, typeList, (*<*)reply)
- ELSE IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
- BEGIN
- (* Launching with documents, so launch applications only *)
- typeList [0] := 'APPL';
- StandardGetFile (NIL, 1, typeList, (*<*)reply)
- END;
-
- IF reply.sfGood THEN
- BEGIN
- launchSpec := reply.sfFile;
-
- (* Check to see if documents should be opened/printed as well *)
- IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
- BEGIN
- (* Create an empty list of documents *)
- docList := CreateDocList (launchMode);
-
- (* Keep getting documents until user chooses Cancel *)
- gettingDocs := TRUE;
- WHILE gettingDocs DO
- BEGIN
- StandardGetFile (NIL, -1, typeList, (*<*)reply);
- IF reply.sfGood THEN
- error := AddToDocList (reply.sfFile, (*◊*)docList)
- ELSE
- gettingDocs := FALSE
- END
- END
- ELSE
- docList := NIL;
-
- (* Attempt to launch the application *)
- LaunchCycle (launchSpec, docList, launchContinue);
-
- (* Dispose of the document list, if there was one *)
- IF docList <> NIL THEN
- DisposeDocList (docList)
- END
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: DoLaunchInBack
- *
- * For the moment, I’m using SFGetFile to choose files rather than
- * StandardGetFile because StandardGetFile has a bug in that file filtering
- * doesn’t work right. This is supposed to be fixed in b2, so I’ll change this
- * call once that version is released. This will make the call to FSMakeFSSpec
- * unnecessary because StandardGetFile returns the FSSpec of the chosen file.
- *******************************************************************************)
-
- PROCEDURE DoLaunchInBack;
-
- VAR
- reply: StandardFileReply; {Reply from SFGetFile}
- typeList: SFTypeList; {List of file types to diplay in SF}
- launchSpec: FSSpec; {Location of selected application}
- docList: DocListHnd; {Handle to the document list}
- gettingDocs: Boolean; {True if user still getting docs}
- launchMode: LaunchModeCode; {Current launch mode}
- error: OSErr;
-
- BEGIN
- (* Get the user’s choice for an application to launch *)
- typeList [0] := 'APPL';
- StandardGetFile (NIL, 1, typeList, (*<*)reply);
-
- IF reply.sfGood THEN
- BEGIN
- (* Convert working directory and file name to FSSpec *)
- launchSpec := reply.sfFile;
-
- launchMode := GetLaunchMode;
- IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
- BEGIN
- (* Create an empty list of documents *)
- docList := CreateDocList (launchMode);
-
- (* Keep getting documents until user chooses Cancel *)
- gettingDocs := TRUE;
- WHILE gettingDocs DO
- BEGIN
- StandardGetFile (NIL, -1, typeList, (*<*)reply);
- IF reply.sfGood THEN
- error := AddToDocList (reply.sfFile, (*◊*)docList)
- ELSE
- gettingDocs := FALSE
- END
- END
- ELSE
- docList := NIL;
-
- (* Attempt to launch the application *)
- LaunchCycle (launchSpec, docList, launchContinue +
- launchDontSwitch);
-
- (* Dispose of the document list, if there was one *)
- IF docList <> NIL THEN
- DisposeDocList (docList)
- END
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: DoLaunchTo
- *
- * For the moment, I’m using SFGetFile to choose files rather than
- * StandardGetFile because StandardGetFile has a bug in that file filtering
- * doesn’t work right. This is supposed to be fixed in b2, so I’ll change this
- * call once that version is released. This will make the call to FSMakeFSSpec
- * unnecessary because StandardGetFile returns the FSSpec of the chosen file.
- *******************************************************************************)
-
- PROCEDURE DoLaunchTo;
-
- VAR
- reply: StandardFileReply; {Reply from SFGetFile}
- typeList: SFTypeList; {List of file types to diplay in SF}
- launchSpec: FSSpec; {Location of selected file}
- docList: DocListHnd; {Handle to the document list}
- gettingDocs: Boolean; {True if user still getting docs}
- launchMode: LaunchModeCode; {Current launch mode}
- error: OSErr;
-
- BEGIN
- (* Get the user’s choice for a file to launch *)
- launchMode := GetLaunchMode;
- IF launchMode = kJustLaunch THEN
- (* Just launching, so launch applications and DAs *)
- StandardGetFile (@AppDAFilter, -1, typeList, (*<*)reply)
- ELSE IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
- BEGIN
- (* Launching with documents, so launch applications only *)
- typeList [0] := 'APPL';
- StandardGetFile (NIL, 1, typeList, (*<*)reply)
- END;
-
- IF reply.sfGood THEN
- BEGIN
- (* Convert working directory and file name to FSSpec *)
- launchSpec := reply.sfFile;
-
- IF (launchMode = kOpenLaunch) OR (launchMode = kPrintLaunch) THEN
- BEGIN
- (* Create an empty list of documents *)
- docList := CreateDocList (launchMode);
-
- (* Keep getting documents until user chooses Cancel *)
- gettingDocs := TRUE;
- WHILE gettingDocs DO
- BEGIN
- StandardGetFile (NIL, -1, typeList, (*<*)reply);
- IF reply.sfGood THEN
- error := AddToDocList (reply.sfFile, (*◊*)docList)
- ELSE
- gettingDocs := FALSE
- END
- END
- ELSE
- docList := NIL;
-
- (* Attempt to launch the application or DA *)
- LaunchCycle (launchSpec, docList, launchAllow24Bit);
-
- (* Dispose of the document list, if there was one *)
- IF docList <> NIL THEN
- DisposeDocList (docList)
- END
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: DoLaunchMode
- *
- * SetLaunchMode does most of the work, and there isn’t much to do.
- *******************************************************************************)
-
- PROCEDURE DoLaunchMode (modeItem: Integer);
-
- BEGIN
- CASE modeItem OF
- iJustLaunch:
- SetLaunchMode (kJustLaunch);
- iOpenLaunch:
- SetLaunchMode (kOpenLaunch);
- iPrintLaunch:
- SetLaunchMode (kPrintLaunch)
- END
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: DoBringProcessToFront
- *
- * The List Manager is called to get each selection in the process list window.
- * SetFrontProcess is called with the process serial number of each selected
- * process. They aren’t immediately brought to the front when SetFrontProcess is
- * called. Instead, they are scheduled to come to the front in the same order as
- * they were presented to SetFrontProcess. Once ProcDoggie reenters the main
- * event loop, the Process Manager brings each scheduled process to the front in
- * turn.
- *
- * At the moment, I can’t get ProcDoggie itself to be scheduled. I assume it’s
- * because SetFrontProcess checks to see if process serial number you passed it
- * is the same as the process serial number of the current process. If it is, it
- * doesn’t bother to schedule the process. I’m not quite sure how to work around
- * that.
- *******************************************************************************)
-
- PROCEDURE DoBringProcessToFront (processListWindow: WindowPtr);
-
- CONST
- kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
-
- VAR
- procList: ListHandle; {Handle to List Mgr process list}
- currCell: Point; {Cell that has selection}
- listInfo: ProcessListInfoRec; {Process info from List Mgr list}
- gotSelection: Boolean; {T if got sel’d cell, F if no more}
- listInfoLen: Integer; {Length of list info in bytes}
- error: OSErr;
-
- BEGIN
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon (processListWindow));
-
- (* Keep looping until all selected processes have been brought to front *)
- currCell.v := 0;
- currCell.h := 0;
- gotSelection := TRUE;
- WHILE gotSelection DO
- BEGIN
- gotSelection := LGetSelect (kFindNext, (*◊*)currCell, procList);
- IF gotSelection THEN
- BEGIN
- listInfoLen := SIZEOF (ProcessListInfoRec);
- LGetCell (Ptr(@listInfo), (*◊*)listInfoLen, currCell,
- procList);
- error := SetFrontProcess (listInfo.serialNumber);
- currCell.v := currCell.v + 1
- END
- END
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: DoGetProcessInfo
- *
- * This routine loops until Process Information windows for all selected
- * processes in the Process List window are displayed. Information for each
- * process in the process list is retrieved from the list itself. Then, that
- * process is compared against all existing Process Information windows. If a
- * Process Information window already exists for that process, then that window
- * is simply activated and DoGetProcessInfo exits. Otherwise, the Process
- * Manager is called to retrieve information for that process. A new Process
- * Information window is created, and its contents are set to the information
- * retrieved for the process.
- *******************************************************************************)
-
- PROCEDURE DoGetProcessInfo (processListWindow: WindowPtr);
-
- CONST
- kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
-
- VAR
- procList: ListHandle; {Handle to List Mgr proc list}
- currCell: Point; {Cell that has selection}
- listInfo: ProcessListInfoRec; {Proc info from List Mgr list}
- gotSelection: Boolean; {T if got sel’d cell, F if none}
- listInfoLen: Integer; {Length of list info in bytes}
- processInfo: ProcessInfoRec; {Info about selected processes}
- procName: Str31; {Name of selected processes}
- procSpec: FSSpec; {File spec of sel’d processes}
- processInfoWindow: WindowPtr; {Ptr to new process info window}
- psnHandle: Handle; {Handle to PSN of chosen proc}
- existingWindow: WindowPtr; {Proc info wind if already open}
- error: OSErr;
-
- PROCEDURE HandleError (messageClass: Integer;
- messageIndex: Integer);
-
- VAR
- result: Integer; {Result of alert; ignored}
-
- BEGIN
- IF processInfoWindow <> NIL THEN
- CloseProcessInfoWindow (processInfoWindow);
- result := ShowStopAlert (messageClass, messageIndex);
- gError := noErr;
- EXIT (DoGetProcessInfo)
- END;
-
- BEGIN
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon (processListWindow));
-
- (* Keep looping until all selected processes have been brought to front *)
- currCell.v := 0;
- currCell.h := 0;
- gotSelection := TRUE;
- WHILE gotSelection DO
- BEGIN
- gotSelection := LGetSelect (kFindNext, (*◊*)currCell, procList);
- IF gotSelection THEN
- BEGIN
- listInfoLen := SIZEOF (ProcessListInfoRec);
- LGetCell (Ptr(@listInfo), (*◊*)listInfoLen, currCell,
- procList);
-
- (* See if proc info wind already exists for selected proc *)
- existingWindow := FindProcessInfoWindow (listInfo.
- serialNumber);
- IF existingWindow <> NIL THEN
- SelectWindow (existingWindow)
- ELSE
- BEGIN
- (* Get information about an open process *)
- processInfo.processInfoLength :=
- SIZEOF (ProcessInfoRec);
- processInfo.processName := @procName;
- processInfo.processAppSpec := @procSpec;
- error := GetProcessInformation (listInfo.serialNumber,
- (*◊*)processInfo);
- IF error <> noErr THEN
- HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
-
- (* Create the process information window *)
- processInfoWindow := CreateProcessInfoWindow;
- IF processInfoWindow <> NIL THEN
- BEGIN
- (* Put handle to PSN into refCon *)
- psnHandle := NewHandleMargin (SIZEOF
- (ProcessSerialNumber), kAllocApp,
- NOT kAllocClr);
- IF psnHandle = NIL THEN
- HandleError (rMemErrMessages,
- kMemErrProcInfoOpenMsg);
- BlockMove (Ptr(@processInfo.processNumber),
- psnHandle^, SIZEOF (ProcessSerialNumber));
- SetWRefCon (processInfoWindow,
- LongInt(psnHandle));
-
- (* Update dlog items to reflect proc info *)
- SetUpProcessInfoItems (processInfoWindow,
- processInfo);
- END
- ELSE
- gotSelection := FALSE
- END;
-
- (* Go to the next cell *)
- currCell.v := currCell.v + 1
- END
- END
- END;
-
-
- {$S ProcessGuts}
- (*******************************************************************************
- * Public: DoTerminateProcess
- *
- * The List Manager is used to get all of the selected processes in
- * processListWindow. The process serial number of each of these processes is
- * extracted and is then used when calling TerminateProcess.
- *******************************************************************************)
-
- PROCEDURE DoTerminateProcess (processListWindow: WindowPtr);
-
- CONST
- kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
-
- VAR
- procList: ListHandle; {Handle to List Mgr process list}
- currCell: Point; {Cell that has selection}
- listInfo: ProcessListInfoRec; {Process info from List Mgr list}
- listInfoLen: Integer; {Length of list info in bytes}
- gotSelection: Boolean; {T if got sel’d cell, F if none}
- error: OSErr;
-
- PROCEDURE HandleError (messageClass: Integer;
- messageIndex: Integer);
-
- VAR
- result: Integer; {Result of alert; ignored}
-
- BEGIN
- result := ShowStopAlert (messageClass, messageIndex);
- gError := noErr;
- EXIT (DoTerminateProcess)
- END;
-
- BEGIN
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon (processListWindow));
-
- (* Keep looping until all selected processes have been terminated *)
- currCell.v := 0;
- currCell.h := 0;
- gotSelection := TRUE;
- WHILE gotSelection DO
- BEGIN
- gotSelection := LGetSelect (kFindNext, (*◊*)currCell, procList);
- IF gotSelection THEN
- BEGIN
- listInfoLen := SIZEOF (ProcessListInfoRec);
- LGetCell (Ptr(@listInfo), (*◊*)listInfoLen, currCell,
- procList);
-
- (* Kill the specified process *)
- error := TerminateProcess (listInfo.serialNumber);
- IF error <> noErr THEN
- HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
-
- (* Go to the next cell *)
- currCell.v := currCell.v + 1
- END
- END
- END;
-